<?php
namespace Tbf\Component\Arrays;

final class ArrayFunction
{
    final private function __construct()
    {
    }
    /**
     * 使用某字段重新写数据的key
     * 使用二维数组里面的某一列的值给第一维重新上key
     * @param  []map[string]string          $data
     * @param  string                       $keyName
     * @return array map[string]map[string]string
     */
    public static function reKeyById(array $data,$keyName='id')
    {
        $output = array();
        foreach ($data as $v1) {
            $output[$v1[$keyName]] = $v1;
        }

        return $output;
    }

    /**
     * 使用对象上面的某个函数重写数据的key
     * @param  []object          $data  不必是array,能foreach就可以了
     * @param  string            $funcName
     * @return array map[string]object
     */
    public static function rekeyByObjectFunction($data,$funcName='getId')
    {
        $output = array();
        foreach ($data as $v1) {
            $output[$v1->$funcName()] = $v1;
        }

        return $output;
    }

    /**
     * 删除所有值为null的项,不修改key
     */
    public static function removeNullValue(array $array)
    {
        foreach ($array as $key=>$value) {
            if (is_null($value)) {
                unset($array[$key]);
            }
        }

        return $array;
    }
    /**
     * 限制数组只包含某些key，去掉其他所有key
     * 备注：不关心原数组是否缺少某些key
     * @param data array 原始数组
     * @param key array 需要的key数组 ''表示不处理
     * @return array 返回数组
     */
    public static function onlyHave(&$data,$key=null)
    {
        if ($key===null) {
            return array();
        }
        if (is_string($key)) {
            $args = func_get_args();
            array_shift($args);

            return self::onlyHave($data,$args);
        }

        return $data = array_intersect_key($data,
            array_fill_keys($key, ''));
    }
    /**
     * 数组key变换
     * 将数组data里面的key,用table进行变换,
     * 1.data多余的key会被删除!
     * 2.table多余的key也不会存在!
     * @param data array
     * @param table array
     */
    public static function keyTran($data,$table)
    {
        $output = array();
        foreach ($table as $origin=>$new) {
            if (!array_key_exists($origin,$data)) {
                continue;
            }
            $output[$new] = $data[$origin];
        }
        return $output;
    }
    /**
     * 二维数组第二维key变换
     * 将数组data里面的key,用table进行变换,
     * 1.data多余的key会被删除!
     * 2.table多余的key也不会存在!
     * 3.第二维按照table的key的顺序排序
     * @param data array
     * @param table array
     * */
    public static function level2KeyTran($data,$table)
    {
        $output = array();
        foreach($data as $k1=>$v1){
            $o1 = array();
            foreach ($table as $origin=>$new) {
                if (!array_key_exists($origin,$v1)) {
                    continue;
                }
                $o1[$new] = $v1[$origin];
            }
            $output[$k1] = $o1;
        }
        return $output;
    }
    /**
     * 数组key变换,忽略不存在
     * 1.递归,扫描所有层次的key
     * 2.忽略不存在table里面的key,->不翻译
     * 可以用于翻译data grid的标题
     * @param $data
     * @param $table
     */
    public static function recursiveIgnoreKeyTran($data,$table){
        $output = array();
        foreach($data as $k=>$v){
            if (isset($table[$k])){
                $k=$table[$k];
            }
            if (is_array($v)){
                $v = self::recursiveIgnoreKeyTran($v,$table);
            }
            $output[$k] = $v;
        }
        return $output;
    }
    /**
     * 将数组中缺少的键赋值为null，
     * 并限制数组只包含某些key，
    @param array $data
    @param array $key
     */
    public static function completeKeys(&$data,$key=null)
    {
        if ($key===null) {
            return $data;
        }
        $key = array_fill_keys($key, null);
        $data = array_intersect_key($data, $key);
        $data = array_merge($key,$data);

        return $data;
    }
    /**
     * 翻译数组
     * 将数组$data里面所有的字符串,都同$table进行变化
    1.如果某个字符串不存在,则保持原样
    2.递归里面所有的数组
     */
    public static function stringTran($data,$table)
    {
        $output = array();
        foreach ($data as $key=>$value) {
            if (isset($table[$key])) {
                $key = $table[$key];
            }
            if (is_string($value)&&isset($table[$value])) {
                $value = $table[$value];
            }
            if (is_array($value)) {
                $value = self::stringTran($value,$table);
            }
            $output[$key] = $value;
        }

        return $output;
    }
    /**
     * 把值是null的元素修改为空字符串''
     * */
    public static function NullValueToEmptyString($data)
    {
        foreach ($data as $key=>$value) {
            if (is_null($value)) {
                $data[$key] = '';
            }
        }

        return $data;
    }
    public static function checkSubArray($origin,$sub)
    {
        foreach ($sub as $key=>$value) {
            if (is_null($value)&&
                is_null($origin[$key])
            ){
                continue;
            }
            if (!isset($origin[$key])) {
                return false;
            }
            if ($origin[$key]!==$value) {
                return false;
            }
        }

        return true;
    }

    /**
     * 返回数组第一个值,
     * 如果数组是空返回null
     * 可以安全的嵌套调用
     *   ArrayFunction::FirstValue(ArrayFunction::FirstValue($data))
     * @param $array array|null
     * @return mixed
     */
    public static function firstValue($array){
        if (empty($array)){
            return null;
        }
        if (is_array($array)){
            return reset($array);
        }
        if (!is_object($array) || !$array instanceof \Traversable){
            throw new \Exception('invalid type of value in ArrayFunction::FirstValue');
        }
        foreach($array as $value){
            return $value;
        }
        return null;
    }

    /**
     * 取出数组某项,如果不存在返回一个默认值
     * 此处保证只要存在就返回值,即使那个值是null
     * @param $array
     * @param $key
     * @param null $default
     * @return null
     */
    public static function defaultParameter($array,$key,$default=null){
        if (!array_key_exists($key,$array)){
            return $default;
        }
        return $array[$key];
    }
    /**
     * 检查里面的所有的字段都存在
     * @param  map[string]interface{} $data
     * @param  []string               $require_list
     * @return null|string            err
     */
    public static function checkParameterExist($data,array $require_list)
    {
        foreach ($require_list as $key) {
            if (!array_key_exists($key,$data)) {
                return 'require parameter '.$key;
            }
        }

        return null;
    }
    /**
     * 检查里面的所有的字段都存在,并且是scalar类型(字符串,整数,浮点)
     * @param  map[string]interface{} $data
     * @param  []string               $require_list
     * @return null|string            err
     */
    public static function checkParameterExistAndScalar($data,array $require_list)
    {
        foreach ($require_list as $key) {
            if (!array_key_exists($key,$data)) {
                return 'require parameter '.$key;
            }
            $value = $data[$key];
            if ( !(is_string($value)|| is_int($value) || is_float($value)) ){
                return sprintf('parameter %s is not string or int or float',$key);
            }
        }

        return null;
    }
    /**
     * 过滤字段
     * @param map[string]interface{} $data
     * @param $allow_list
     * @return map[string]interface{}
     */
    public static function filterParameter($data,array $allow_list)
    {
        foreach ($data as $key=>$value) {
            if (!in_array($key,$allow_list)) {
                unset($data[$key]);
            }
        }

        return $data;
    }

    /**
     * 交换一个数组的key和value
     * 忽略值不是string int的数据
     * @param $data
     */
    public static function exchangeKeyValue($data){
        $output = array();
        foreach($data as $key=>$value){
            if (is_string($value)||is_int($value)){
                $output[$value] = $key;
            }
        }
        return $output;
    }
    /**
     * 列子矩阵
     * 1.所有行必须完全匹配
     * 2.每一行可以用不同的列包含.
     * 元素匹配使用===
     * */
    public static function checkColumnSubMatrix($origin,$sub)
    {
        foreach ($origin as $k1=>$row) {
            if (empty($sub[$k1])) {
                return false;
            }
            foreach ($sub[$k1] as $k2=>$v2) {
                if (is_null($v2)) {
                    if (is_null($origin[$k1][$k2])) {
                        continue;
                    } else {
                        return false;
                    }
                }
                if (!isset($origin[$k1][$k2])) {
                    return false;
                }
                if ($origin[$k1][$k2]!==$sub[$k1][$k2]) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * 使用交替的方法将二维数组扁平化为一维数组
     * @param $data
     * @return array
     */
    public static function inTurnFlatLevel2Array($data){
        $output = array();
        $l1_key_list = array_keys($data);
        //不能foreach $data 会死循环
        foreach($l1_key_list as $k1){
            reset($data[$k1]);
        }
        while(true){
            $has_data = false;
            foreach($l1_key_list as $k1){
                if (key($data[$k1]) === null) {
                    continue;
                }
                $output[] = current($data[$k1]);
                $has_data =true;
                next($data[$k1]);
            }
            if ($has_data===false){
                break;
            }
        }
        return $output;
    }
}
